package com.wizz.trade.trading.controller;

import com.wizz.trade.common.PageVo;
import com.wizz.trade.common.ResponseResult;

import com.wizz.trade.common.constant.StatusCode;
import com.wizz.trade.information.entity.Variety;
import com.wizz.trade.information.mapper.VarietyMapper;
import com.wizz.trade.trading.dto.*;
import com.wizz.trade.trading.dto.page.ImportCostPageDto;
import com.wizz.trade.trading.dto.page.PositionPageDto;
import com.wizz.trade.trading.dto.page.TradePageDto;
import com.wizz.trade.trading.entity.ImportCost;
import com.wizz.trade.trading.entity.Position;
import com.wizz.trade.trading.entity.Trade;
import com.wizz.trade.trading.service.ImportCostService;
import com.wizz.trade.trading.service.PositionService;
import com.wizz.trade.trading.service.TradeService;
import com.wizz.trade.trading.vo.*;
import com.wizz.trade.util.FileOperationUtil;
import com.wizz.trade.util.SeqIdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.CacheManager;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 贸易模块/购销订单
 */
@RestController
@Slf4j
@RequestMapping("/trade")
public class TradeFirstController {

    @Resource
    private TradeService tradeService;

    @Resource
    private PositionService positionService;

    @Resource
    private ImportCostService importCostService;

    @Resource
    private VarietyMapper varietyMapper;

    @Resource
    private CacheManager cacheManager;

    @Resource
    private SeqIdGenerator seqIdGenerator;

    /**
     * 采购操作
     * 表：写“购销表”采购记录，“持仓表”
     * 1.程序的起始，弹出对话框，录入采购数据。
     * 2.录入《确认》完成后，新建数据写入“购销表”同时写入“持仓表”。
     * 3.写持仓表时，计算出相应的数据，应占用库存资金等…。Storage_capital.
     *
     * @return
     */
    @PostMapping("/purchase")
    public ResponseResult<String> purchase(@RequestBody TradePurchaseDto tradePurchaseDto) {
        //参数校验
        //此处的bigdecimal类型的采购数量必须大于0且为整数
        boolean realQtyFlag = tradePurchaseDto.getRealqty().compareTo(BigDecimal.ZERO) <= 0 ||
                tradePurchaseDto.getRealqty().stripTrailingZeros().scale() > 0;
        if (realQtyFlag) {
            return new ResponseResult<>(StatusCode.PARAMERROR, "采购数量必须大于0且为整数");
        }
        //订单价格必须大于0
        if (tradePurchaseDto.getAtPrice().compareTo(BigDecimal.ZERO) <= 0) {
            return new ResponseResult<>(StatusCode.PARAMERROR, "订单价格必须大于0");
        }

        Trade trade = new Trade();
        BeanUtils.copyProperties(tradePurchaseDto, trade);
        Variety variety = varietyMapper.selectById(tradePurchaseDto.getVarietyId());
        trade.setUnit(variety.getUnit());
        trade.setVat(variety.getVat());
        StringBuilder sb1 = new StringBuilder();
        sb1.append(trade.getLedgerId());
        sb1.append(trade.getOurDeptId());
        sb1.append(trade.getDate().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        String prefix1 = sb1.toString();
        trade.setBatchNo(prefix1 + seqIdGenerator.generateAutoIncreaseSeqId(prefix1, 3));
        StringBuilder sb2 = new StringBuilder();
        sb2.append("0");
        sb2.append(trade.getPs());
        sb2.append(trade.getLedgerId());
        sb2.append(trade.getVarietyId());
        sb2.append(trade.getDate().format(DateTimeFormatter.ofPattern("yyyyMM")));
        String prefix2 = sb2.toString();
        trade.setOrderNo(prefix2 + seqIdGenerator.generateAutoIncreaseSeqId(prefix2, 3));
        tradeService.addTrade(trade);

        Position position = new Position();
        position.setLedger(trade.getLedgerId());
        position.setOurDept(trade.getOurDeptId());
        position.setCompany(trade.getCompanyId());
        position.setCompanyDept(trade.getCompanyDeptId());
        position.setVariety(trade.getVarietyId());
        position.setGrade(trade.getGradeId());
        position.setTrademark(trade.getTrademarkId());
        position.setCprice(trade.getAtPrice());
        position.setPtcprice(trade.getAtPrice().multiply(BigDecimal.valueOf(1).add(trade.getVat())));
        //现货结算价需要单独输入
        position.setSprice(null);
        position.setOi(trade.getRealqty());
        //浮盈在结算价给出后得到
        position.setFpl(null);
        position.setStorageCapital(position.getCprice().multiply(position.getOi()));
        position.setBatchNo(trade.getBatchNo());
        position.setDate(trade.getDate());
        position.setPattern(trade.getPattern());
        position.setDeliver(trade.getDeliver());
        position.setOrderId(trade.getOrderId());
        position.setUnit(trade.getUnit());
        position.setCurrency(trade.getCurrencyId());
        positionService.addPosition(position);

        ImportCost importCost = new ImportCost();
        importCost.setPosition(position.getId());
        importCostService.addImportCost(importCost);
        return new ResponseResult<>(StatusCode.OK, "添加成功");
    }

    /**
     * 销售确认
     *
     * 表：读、写“持仓表”，写“购销表”，写“毛利表”
     * 1.在现货持仓种勾选一条或多条记录，弹出销售对话框，可双击弹出。
     * 2.多条需判断条件，条件：账套、业务部门、品种相同。
     * 3.计算持仓表中相应的数据，现货持仓量oi，应占用库存资金等…。
     * 4.计算毛利表中相应的数据，含税毛利、不含税毛利。
     *
     * @param tradeSaleDto
     * @return
     */
    @PostMapping("/sale")
    public ResponseResult<String> sale(@RequestBody TradeSaleDto tradeSaleDto) {
        TradePurchaseDto tradePurchaseDto = tradeSaleDto.getTradePurchaseDto();

        //设置trade信息
        Trade trade = new Trade();
        BeanUtils.copyProperties(tradePurchaseDto, trade);
        StringBuilder sb1 = new StringBuilder();
        sb1.append(trade.getLedgerId());
        sb1.append(trade.getOurDeptId());
        sb1.append(trade.getDate().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        String prefix1 = sb1.toString();
        trade.setBatchNo(prefix1 + seqIdGenerator.generateAutoIncreaseSeqId(prefix1, 3));
        StringBuilder sb2 = new StringBuilder();
        sb2.append("0");
        sb2.append(trade.getPs());
        sb2.append(trade.getLedgerId());
        sb2.append(trade.getVarietyId());
        sb2.append(trade.getDate().format(DateTimeFormatter.ofPattern("yyyyMM")));
        String prefix2 = sb2.toString();
        trade.setOrderNo(prefix2 + seqIdGenerator.generateAutoIncreaseSeqId(prefix2, 3));

        List<Position> positions = tradeSaleDto.getPositionDtos().stream().map((item)->{
            Position position = new Position();
            BeanUtils.copyProperties(item, position);
            return position;
        }).collect(Collectors.toList());

        tradeService.sale(trade, positions);
        return new ResponseResult<>(StatusCode.OK, "新增记录成功");
    }

//    /**
//     * 订单扫描件上传
//     * @param multipartFile 上传的文件
//     * @return 上传结果
//     */
//    @PostMapping("/image")
//    public ResponseResult<String> uploadImage(@RequestParam("file")MultipartFile multipartFile){
//        String url = fileOperationUtil.uploadImage(multipartFile);
//        return new ResponseResult<>(StatusCode.OK, "上传成功", url);
//    }

    /**
     * 销售发起
     * @param ids
     * @return
     */
    @GetMapping("/sale")
    public ResponseResult<List<Position>> prepareForSale(@RequestBody List<Integer> ids){
        List<Position> list = new ArrayList<>();
        for (Integer id : ids) {
            Position position = positionService.getById(id);
            list.add(position);
        }
        return new ResponseResult<>(StatusCode.OK, list);
    }

    /**
     * 现货结算价发起
     * 用于点击现货结算价按钮后，将账套、品种、规格、商标均相同的项合并显示。
     * @return
     */
    @GetMapping("/sprice")
    public ResponseResult<List<GetSPriceVo>> getSpriceIds(){
        List<GetSPriceVo> result = positionService.getSettlementPrice();
        return new ResponseResult<>(StatusCode.OK, "查询成功", result);
    }

    /**
     * 现货结算价确认
     * 表：写“持仓表”、“进口成本参考表”
     * 1.弹出结算价录入对话框，从持仓表中，筛选出账套、部门、品种、规格相同的，持仓量≠0的记录，显示到对话框中。
     * 2.输入每笔记录的币种结算价、本币结算价。
     * 3.计算出持仓表中，每笔现货持仓浮动盈亏、进口参考成本浮动盈亏。Fpl
     * 4.对筛选出的持仓记录，汇总计算出现货持仓量汇总、现货浮动盈亏汇总、应占用库存资金汇总等结果，写入现货盈亏每日汇总表中。
     * 5.从毛利表中，筛选出账套、部门、品种、规格相同的记录，计算当日、累计销售额等，写入现货盈亏每日汇总表中。
     *
     * @param list 同时可以处理很多持仓信息，组成一个数组
     * @return
     */
    @PutMapping("/sprice")
    public ResponseResult<String> setSprice(@RequestBody List<SpotSettlementPriceDto> list) {
        positionService.setSettlementPrice(list);
        return new ResponseResult<>(StatusCode.OK, "更新成功");
    }

    /**
     * 设置汇率
     * @param list
     * @return
     */
    @PutMapping("/import")
    public ResponseResult<String> setExrate(@RequestBody List<SpotExrateDto> list){
        importCostService.setExRate(list);
        return new ResponseResult<>(StatusCode.OK, "设置成功");
    }

    /**
     * 发起汇率
     * @return
     */
    @GetMapping("/import")
    public ResponseResult<Map<String, String>> getExrate(){
        Map<String, String> resultMap = importCostService.getExRate();
        return new ResponseResult<>(StatusCode.OK, "查询成功", resultMap);
    }

    /**
     * 查看库存明细
     * 
     * 前端传入现货持仓的某一条id，返回明细
     * @param positionId
     * @return
     */
    @GetMapping("/check")
    public ResponseResult<List<InventoryDetailVo>> check(Integer positionId){
        return null;
    }

    /**
     * 查询贸易记录
     * @param tradePageDto
     * @return
     */
    @GetMapping("/trade/page")
//    @Cacheable(value = "tradeCache", key = "'trade_' + T(java.util.Objects).hash(#tradePageDto)")
    public ResponseResult<PageVo<TradeForFirstPageVo>> getTradePage(TradePageDto tradePageDto){
        PageVo<TradeForFirstPageVo> page = tradeService.getPageForFirstPage(tradePageDto);
        return new ResponseResult<>(StatusCode.OK, "查询成功", page);
    }

    /**
     * 查询持仓记录
     * @param positionPageDto
     * @return
     */
    @GetMapping("/position/page")
//    @Cacheable(value = "tradeCache", key = "'position_' + T(java.util.Objects).hash(#positionPageDto)")
    public ResponseResult<PageVo<PositionVo>> getPositionPage(PositionPageDto positionPageDto){
        PageVo<PositionVo> page = positionService.getPage(positionPageDto);
        return new ResponseResult<>(StatusCode.OK, "查询成功", page);
    }

    /**
     * 查询进口成本参考表
     * @param importCostPageDto
     * @return
     */
    @GetMapping("/importcost/page")
//    @Cacheable(value = "tradeCache", key = "'importcost_' + T(java.util.Objects).hash(#importCostPageDto)")
    public ResponseResult<PageVo<ImportCostVo>> getImportCostPage(ImportCostPageDto importCostPageDto){
        PageVo<ImportCostVo> page = importCostService.getPage(importCostPageDto);
        return new ResponseResult<>(StatusCode.OK, "查询成功", page);
    }
}
